using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

using MapWindow.Main.EventArguments;
using MapWindow.Geometries;


namespace MapWindow.Data
{
    /// <summary>
    /// A generic vector feature that has the geometry and data components but no drawing information
    /// </summary>
    public class Feature : Object, IFeature, IBasicGeometry
    {

        #region Variables

        /// <summary>
        /// A cache of the datarow for this specific member.  This is only cached if it is requested at
        /// least once.
        /// </summary>
        protected System.Data.DataRow _DataRow;

        /// <summary>
        /// A local geometry base
        /// </summary>
        protected IBasicGeometry _BasicGeometry;
        
        /// <summary>
        /// The feature id, which for shapefiles indicates the row number
        /// </summary>
        protected int _FID;

        /// <summary>
        /// The layer that stores this feature.  If a Parent exists, then
        /// a query by FID is possible to fill in the data row if needed.
        /// </summary>
        protected IFeatureLayer _ParentFeatureLayer;

        /// <summary>
        /// This particular implementation of the Feature uses offsets like an index to keep track of where 
        /// this feature is currently stored in the file.
        /// </summary>
        protected long _Offset;

        #endregion 

        #region Constructors

        /// <summary>
        /// Constructs a new Feature
        /// </summary>
        public Feature()
        {
            _DataRow = null;
            _BasicGeometry = null;
        }

        /// <summary>
        /// This constructor essentially copies the important information from the specified IFeature
        /// </summary>
        /// <param name="fromFeature">Any valid implementation of IFeature</param>
        public Feature(IFeature fromFeature)
        {
           
            _DataRow = fromFeature.DataRow;
            _BasicGeometry = fromFeature.BasicGeometry;

            // The following are supposed to be unique and shouldn't be copied to a new feature
            // _FID = fromFeature.FID;
            // _ParentFeatureLayer;
            // _Offset = fromFeature.Offset;

        }

        /// <summary>
        /// This returns itself as the first geometry
        /// </summary>
        /// <returns>An IBasicGeometry interface</returns>
        /// <exception cref="IndexOutOfRangeException">Index cannot be less than 0 or greater than 1</exception>
        public IBasicGeometry GetBasicGeometryN(int index)
        {
            return _BasicGeometry.GetBasicGeometryN(index);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates a deep copy of this feature.
        /// </summary>
        /// <returns></returns>
        public virtual object Clone()
        {
            return base.MemberwiseClone();
        }


        /// <summary>
        /// Non-Topology Intersection functions 
        /// </summary>
        /// <param name="X">The double X coordinate or longitude</param>
        /// <param name="Y">The double Y coordinate or latitude</param>
        /// <returns>Boolean, true if this geometry intersects with a point that has the given coordinates</returns>
        public virtual bool Intersects(double X, double Y)
        {
            return _BasicGeometry.Intersects(X, Y);
        }

        /// <summary>
        /// Tests for an intersection with the specified envelope.
        /// </summary>
        /// <param name="env">Any valid IEnvelope to compare against</param>
        /// <returns>Boolean, true if this geometry intersects with the given shape.</returns>
        public virtual bool Intersects(IEnvelope env)
        {
            return _BasicGeometry.Intersects(env);
        }

        /// <summary>
        /// Returns the Well-known Binary representation of this <c>Geometry</c>.
        /// For a definition of the Well-known Binary format, see the OpenGIS Simple
        /// Features Specification.
        /// </summary>
        /// <returns>The Well-known Binary representation of this <c>Geometry</c>.</returns>
        public virtual byte[] ToBinary()
        {
            return _BasicGeometry.ToBinary();
        }

        #endregion

        /// <summary>
        /// Returns a valid IBasicGeometry associated with the data elements of this feature.
        /// This will be enough geometry information to cast into a full fledged geometry
        /// that can be used in coordination with MapWindow.Tools
        /// </summary>
        public virtual IBasicGeometry BasicGeometry
        {
            get
            {
                return _BasicGeometry;
            }
            set
            {
                _BasicGeometry = value;
            }
        }

        /// <summary>
        /// Returns an array of coordinates corresponding to the basic feature.
        /// </summary>
        public virtual ICoordinate[] Coordinates
        {
            get { return _BasicGeometry.Coordinates; }   
        }

        /// <summary>
        /// Gets the datarow containing all the attributes related to this geometry.
        /// This will query the parent feature layer's data table by FID and then
        /// cache the value locally.  If no parent feature layer exists, then
        /// this is meaningless.  You should create a new Feature by doing
        /// FeatureLayer.Features.Add(), which will return a new Feature.
        /// </summary>
        public virtual System.Data.DataRow DataRow
        {
            get
            {
                if (_DataRow == null)
                {
                    // TO DO: Read based on FID.  This would not be used in the ShapefileEditor
                    // but would enable dynamic loading of data rows.
                }
                return _DataRow;
            }
            internal set
            {
                _DataRow = value;
            }
        }

        /// <summary>
        /// Gets the envelope of this point... which is technically just the same value
        /// for both extremes
        /// </summary>
        public virtual IEnvelope Envelope
        {
            get { return _BasicGeometry.Envelope; }
        }

        /// <summary>
        /// Creates a new GML string describing the location of this point
        /// </summary>
        /// <returns>A String representing the Geographic Markup Language version of this point</returns>
        public virtual string ExportToGML()
        {
            return _BasicGeometry.ExportToGML();
        }



        /// <summary>
        /// Returns either Point, Polygon or Line
        /// </summary>
        public FeatureTypes FeatureType
        {
            get { return _BasicGeometry.FeatureType; }
        }
       

        /// <summary>
        /// Gets the key that is associated with this feature.  This returns -1 if
        /// this feature is not a member of a feature layer.
        /// </summary>
        public virtual int FID
        {
            get
            {
                return _FID;
            }
        }
        

        /// <summary>
        /// Shows the type of geometry for this feature
        /// </summary>
        public virtual string GeometryType
        {
            get
            {
                return _BasicGeometry.GeometryType;
            }
        }

       

        /// NumGeometries
        /// <summary>
        /// This always returns 1
        /// </summary>
        public virtual int NumGeometries
        {
            get {  return _BasicGeometry.NumGeometries; }
          
        }

        /// <summary>
        /// This always returns 1
        /// </summary>
        public virtual int NumPoints
        {
            get { return _BasicGeometry.NumPoints; }
        }


        
        /// <summary>
        /// This specifies the offset, if any in the data file
        /// </summary>
        public long Offset
        {
            get
            {
                return _Offset;
            }
            internal set // like VB. Friend, allow MapWindow to control _Offset, but not outside users
            {
                _Offset = value;
            }
        }

        /// <summary>
        /// Gets a reference to the IFeatureLayer that contains this item.
        /// </summary>
        public virtual IFeatureLayer ParentFeatureLayer
        {
            get { return _ParentFeatureLayer; }
            set { _ParentFeatureLayer = value; }
        }

       



    }
}
